<?php
/**
 * Created by PhpStorm.
 * User: FoxxxZhu
 * Date: 2018/6/8
 * Time: 10:43
 */

namespace Forxx;


use Lavender\Core;
use Lavender\Errno;
use Lavender\Exception;
use Lavender\Filter;
use Lavender\Session;

class ForxxAppService extends ForxxWebService{

    protected $need_check_req_time = true;
    protected $loginKeyPre = "app_info::";
    protected $tokenKeyPre = "token::";
    protected $userDataKeyPre = "user_data::";
    protected $without_check_req_time_actions = [];
    protected $appInfo = [];

    public function before_execute()
    {
        if($this->need_auth){
            if(array_search($this->action_name, $this->without_auth_actions) !== false || array_search('*', $this->without_auth_actions) !== false){
                $this->need_auth = false;
            }
        }
        if($this->need_sign){
            if(array_search($this->action_name, $this->without_sign_actions) !== false || array_search('*', $this->without_sign_actions) !== false){
                $this->need_sign = false;
            }
        }
        if($this->need_check_req_time){
            if(array_search($this->action_name, $this->without_check_req_time_actions) !== false || array_search('*', $this->without_check_req_time_actions) !== false){
                $this->need_check_req_time = false;
            }
        }
    }

    public function check_req_time(){
        if($this->need_check_req_time){
            $params = $this->parameters([
                '_rt'=>Filter::T_INT,
                '_rtk'=>Filter::T_STRING,
            ],self::M_GET, true);
            $req = $params['_rt'];
            $key = $params['_rtk'];
            $loginInfo = $this->get_user_data();
            $appKey = isset($loginInfo['app_key']) ? $loginInfo['app_key'] : "";
            if($req - time() > 10){
                throw new Exception\Auth('req time invalid', Errno::AUTH_FAILED);
            }
            if(time() - $req > 30){
                throw new Exception\Auth('req is expired!', Errno::AUTH_FAILED);
            }
            if($key !== md5(md5($req).$appKey))
            {
                throw new Exception\Auth('req key is error!', Errno::AUTH_FAILED);
            }
        }
    }

    protected function check_sign()
    {
        if($this->need_sign){
            $sign_field_name = $this->sign_field_name;
            $req = array(
                'ver' => Filter::T_STRING,
                'token' => Filter::T_STRING,
                $sign_field_name => Filter::T_STRING,
            );
            $params = $this->parameters($req, self::M_GET, true);
            $this->sign = $params[$sign_field_name];
            $request = $this->get_request_param();
            $token = $params['token'];
            if(empty($token))
            {
                throw new Exception\Auth('token missed', Errno::AUTH_FAILED);
            }
            if(empty($this->sign))
            {
                throw new Exception\Auth($sign_field_name.' missed', Errno::AUTH_FAILED);
            }
            if(!$this->is_valid_signature($token, $request, $this->sign))
            {
                throw new Exception\Auth('sign verify failed : '.$this->sign, Errno::AUTH_FAILED);
            }
        }
    }

    protected function check_auth()
    {
        $req = array(
            'token' => Filter::T_STRING,
        );
        $params = $this->parameters($req, self::M_GET, true);
        $this->recover_user_data($params['token']);
        if($this->need_auth){
            if($this->uid < 1){
                throw new Exception\Auth('lose login info', Errno::AUTH_FAILED);
            }
        }
    }

    protected function recover_user_data($token)
    {
        $cacheKey = $this->tokenKeyPre.$token;
        $uid = RedisCache::instance()->get($cacheKey);
        if(!empty($uid)){
            $this->uid = $uid;
            return true;;
        }
        return false;
    }

    public function login($uid,$token = null,$setCookie = true)
    {
        $timeout = isset($this->options['session_timeout']) ? $this->options['session_timeout'] : 0;
        $cacheKey = $this->loginKeyPre.md5($uid);
        $token = md5(date("mdHis").uniqid().$uid);
        $this->uid = $uid;
        RedisCache::instance()->set($cacheKey,$token,$timeout);
        RedisCache::instance()->set($this->tokenKeyPre.$token,$uid,$timeout);
        return $token;
    }

    protected function logout()
    {
        $this->session->destroy();
    }

    protected function set_user_data($data){
        if($this->uid < 1){
            return false;
        }
        $cacheKey = $this->userDataKeyPre.$this->uid;
        RedisCache::instance()->set($cacheKey,$data);
    }

    protected function get_user_data(){
        if($this->uid < 1){
            return [];
        }
        $cacheKey = $this->userDataKeyPre.$this->uid;
        $userData =  RedisCache::instance()->get($cacheKey);
        return $userData;
    }
}